﻿/*****************************************************************//**
 * @file    PickedData.h
 * @brief   拾取数据类。
 *
 * @author  ChengHaotian (yeguangbaozi@foxmail.com)
 * @date    2024-10-31
 *********************************************************************/

#ifndef __PICKEDDATA_H__
#define __PICKEDDATA_H__

#include <QObject>

#include "PickDataProviderAPI.h"

#include "GUIPickInfo.h"

#include <QHash>

#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSysWithNodes.h"

 // 前置声明
class vtkActor;
class vtkActor2D;
class vtkImageActor;
class vtkPlanes;
class vtkUnstructuredGrid;

namespace Exchange
{
    class FITKAcousticsVTKGraphObject3D;
}

namespace GraphData
{
    /**
     * @brief   拾取的数据类型。
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-10-31
     */
    enum PickedDataType
    {
        OtherPick = -1,

        // 几何。
        GeoVertPick = 0,
        GeoEdgePick,
        GeoFacePick,
        GeoSolidPick,

        // 网格。
        MeshCellPick,
        
        // SEA子系统。
        DiscNodePick,
        SEABeamPick,
        SEAShellPick,
        SEACavityPick,
        SEASemiInfFluidPick,

        // SEA连接关系。
        JuncPointPick,
        JuncLinePick,
        JuncAreaPick,

        //载荷
        LoadPointForcePick,
        LoadPowerPick,
        LoadConstraintPick,
        LoadImportPick,
        LoadExcForMomPick,
        LoadMonopolePick,

        //FE子系统
        FEFacePick,
        FEStructureShellPick,
        FEStructureBeamPick,
        FEAcousticPick,

        //传感器
        FESensorPick,
    };

    /**
     * @brief   进行拾取操作时的鼠标操作方式。
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-10-31
     */
    enum PickedMouseType
    {
        PickedNoneType = -1,
        PickedMouseClick = 0,
        PickedMouseRubber
    };

    /**
     * @brief   面拾取数据结构体。
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-11-22
     */
    struct PickedFaceData
    {
        int FaceId = -1;
        int ElementId = -1; // 索引。
    };

    /**
     * @brief   拾取数据类。（并未三维可视化对象）
     * @author  ChengHaotian (yeguangbaozi@foxmail.com)
     * @date    2024-10-31
     */
    class PICKDATAPROVIDERAPI PickedData : public QObject
    {
        Q_OBJECT
    public:
        /**
         * @brief   构造函数。（点击拾取）
         * @param   pickedInfo：拾取时的类型、方法等相关信息
         * @param   pickedActor：被拾取的演员
         * @param   pickedIndex：拾取时的索引
         * @param   pickedWorldPos：拾取的世界坐标
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedData(GUI::GUIPickInfoStru pickedInfo, vtkActor* pickedActor, int pickedIndex, double* pickedWorldPos);

        /**
         * @brief   构造函数。（点击拾取）
         * @param   pickedInfo：拾取时的类型、方法等相关信息
         * @param   pickedActor：被拾取的演员
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedData(GUI::GUIPickInfoStru pickedInfo, vtkActor2D* pickedActor);

        /**
         * @brief   构造函数。（点击拾取）
         * @param   pickedInfo：拾取时的类型、方法等相关信息
         * @param   pickedActor：被拾取的演员
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-07
         */
        PickedData(GUI::GUIPickInfoStru pickedInfo, vtkImageActor* pickedActor);

        /**
         * @brief   构造函数。（框选拾取）
         * @param   pickedInfo：拾取时的类型、方法等相关信息
         * @param   pickedActor：被拾取的演员
         * @param   pickPlanes：拾取时拾取器裁切平面
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-02
         */
        PickedData(GUI::GUIPickInfoStru pickedInfo, vtkActor* pickedActor, vtkPlanes* pickPlanes);

        /**
         * @brief   析构函数。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        ~PickedData();

        /**
         * @brief   保存拾取时键盘按下情况。
         * @param   qKey：键盘按键值
         * @param   flag：是否按下
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-08
         */
        void saveKeyFlags(Qt::Key qKey, bool flag);

        /**
         * @brief   保存拾取到的可视化对象。
         * @param   obj：可视化对象
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void setPickedGraphObject(Exchange::FITKAcousticsVTKGraphObject3D* obj);

        /**
         * @brief   获取拾取到的可视化对象。
         * @return  可视化对象
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        Exchange::FITKAcousticsVTKGraphObject3D* getPickedGraphObejct();
        
        /**
         * @brief   拷贝数据。（此方法仅用于预选高亮转拾取高亮使用。）
         * @return  拷贝的数据
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedData* getCopy();

        /**
         * @brief   排序。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void sortIds();

        /**
         * @brief   判断两份数据是否属于相同数据源或完全相同。
         * @param   data：待检测数据
         * @param   checkIds：是否比对拾取到的数据ID[缺省]
         * @return  是否为相同模型或完全一致
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool isSameAs(PickedData* data, bool checkIds = false);

        /**
         * @brief   为ID列表数据进行排序。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void sort();

        /**
         * @brief   合并两份数据。（A + B）
         * @param   data：待合并数据
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void add(PickedData* data);

        /**
         * @brief   移除部分数据。（A - B）
         * @param   data：待移除数据
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void subtract(PickedData* data);

        /**
         * @brief   融合两份数据。
         *          （根据拾取模式与数据自行判断进行增量或减量拾取）
         * @param   data：待合并数据
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-05
         */
        void merge(PickedData* data);

        /**
         * @brief   判断该次拾取是否有效。
         * @return  是否有效
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool isValid();

        /**
         * @brief   获取当前数据是否为空。
         * @return  是否为空
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool isEmpty();

        /**
         * @brief   判断该次拾取是否结束。
         * @return  是否结束
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-01
         */
        bool isFinished();

        /**
         * @brief   判断当前数据是否包含给定的演员与索引。
         * @param   actor：演员
         * @param   index：索引
         * @return  是否包含
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool contains(vtkActor* actor, int index);

        /**
         * @brief   判断当前数据是否包含给定的演员。
         * @param   actor：演员
         * @return  是否包含
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool contains(vtkActor2D* actor);

        /**
         * @brief   获取拾取类型等信息。
         * @return  拾取方式信息
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        GUI::GUIPickInfoStru getPickedInfo();

        /**
         * @brief   获取被拾取的演员。
         * @return  被拾取的演员
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        vtkActor* getPickedActor();

        /**
         * @brief   获取被拾取的索引。
         * @return  被拾取索引
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        int getPickedIndex();

        /**
         * @brief   获取拾取时的鼠标拾取方式。
         * @return  鼠标拾取方式（点击或框选，如果该数据已被计算成实际的拾取信息则返回-1）
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedMouseType getPickedMouseType();

        /**
         * @brief   获取拾取到的世界坐标。
         * @param   pos：世界坐标
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void getPickedWorldPosition(double* pos);

        /**
         * @brief   高亮/预选高亮可视化对象。（内部根据拾取数据类型自动判断）
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void highlight();

        /**
         * @brief   取消高亮。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void clearHighlight();

        /**
         * @brief   设置计算完成标识。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void calculateFinsish();

        /**
         * @brief   是否需要进行计算。
         * @return  是/否
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool needToCalculate();

        /**
         * @brief   获取拾取数据类型。
         * @return  拾取类型
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedDataType getPickedDataType();

        /**
         * @brief   获取拾取时的裁切屏幕。
         * @return  裁切平面信息
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-02
         */
        vtkPlanes* getPickPlanes();

        /**
         * @brief   获取拾取数据ID。
         * @return  拾取数据列表[引用]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        QList<int> & getPickedIds();
        /**
         * @brief    添加额外数据id
         * @param[i] pickId                 数据id
         * @param[i] pickOtherId            额外数据id
         * @author   BaGuijun (baguijun@163.com)
         * @date     2025-01-02
         */
        void appendPickedOtherId(int pickId, int pickOtherId);
        /**
         * @brief    获取额外数据id
         * @return   QHash<int,int>          <数据id，额外数据id>
         * @author   BaGuijun (baguijun@163.com)
         * @date     2025-01-02
         */
        QHash<int, int> getPickedOtherIDs();
        /**
         * @brief   设置拾取到的数据ID。
         * @param   dataObjId：数据ID
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-18
         */
        void savePickedDataObjId(int dataObjId);

        /**
         * @brief   获取拾取到的数据ID。
         * @return  数据对象ID
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        int getPickedDataObjId();

        // 特殊拾取数据获取接口。
        //@{
        /**
         * @brief   获取拾取到的SEA节点。
         * @return  SEA节点列表（含节点类型）[引用]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-01
         */
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> & getPickedDiscNodes();

        /**
         * @brief   获取拾取到的SEA面。
         * @return  SEA面列表[引用]
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-22
         */
        QList<PickedFaceData> & getPickedSEAFaces();
        //@}
        
    private:
        /**
         * @brief   构造函数。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedData();

        /**
         * @brief   初始化演员拾取，获取拾取演员中存储的信息。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void init();

        /**
         * @brief   初始化2D演员拾取，获取拾取演员中存储的信息。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void init2D();

        /**
         * @brief   初始化图片演员拾取，获取拾取演员中存储的信息。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-07
         */
        void initImage();

        /**
         * @brief   初始化拾取对象类。
         * @return  是否为支持的拾取对象类型
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-07
         */
        bool initPickObjType();

    private slots:
        /**
         * @brief   清空可视化对象指针。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        void slot_resetGraphObject();

    private:
        // 拾取时的信息。
        //@{
        /**
         * @brief   被拾取时的拾取类型。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        GUI::GUIPickInfoStru m_pickedInfo;

        /**
         * @brief   拾取时的演员。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        vtkActor* m_pickedActor{ nullptr };

        /**
         * @brief   拾取时的2D演员。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        vtkActor2D* m_pickedActor2D{ nullptr };

        /**
         * @brief   拾取时的图片演员。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-07
         */
        vtkImageActor* m_pickedActorImg{ nullptr };

        /**
         * @brief   框选区域。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-02
         */
        vtkPlanes* m_pickPlanes{ nullptr };

        /**
         * @brief   拾取时的索引。（VTK数据索引）
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        int m_pickedIndex = -1;

        /**
         * @brief   拾取时的鼠标操作。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedMouseType m_mouseOper = PickedMouseType::PickedNoneType;

        /**
         * @brief   拾取到的世界坐标。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        double m_pickedWorldPos[3]{ 0, 0, 0 };

        /**
         * @brief   是否需要进行计算。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool m_needToCal = false;

        /**
         * @brief   是否有效。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        bool m_isValid = false;

        /**
         * @brief   拾取到的数据类型。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        PickedDataType m_type = PickedDataType::OtherPick;

        /**
         * @brief   键盘按下情况字典。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-08
         */
        QHash<Qt::Key, bool> m_keyFlagsHash;

        /**
         * @brief   拾取到的ID列表。（OCC形状ID）
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        QList<int> m_ids;
        /**
         * @brief  拾取到的额外数据id
         * @author BaGuijun (baguijun@163.com)
         * @date   2025-01-02
         */
        QHash<int, int> m_otherIds = {};

        /**
         * @brief   SEA节点列表。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-01
         */
        QList<Acoustics::FITKAbstractSEASubSysWithNodes::SubSysNode> m_seaNodes;

        /**
         * @brief   SEA面列表。（仅点选模式支持存储该数据）
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-11-22
         */
        QList<PickedFaceData> m_seaFaces;

        // 数据ID。
        //@{
        /**
         * @brief   数据对象ID。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        int m_dataObjId = -1;

        /**
         * @brief   拾取到的可视化对象。
         * @author  ChengHaotian (yeguangbaozi@foxmail.com)
         * @date    2024-10-31
         */
        Exchange::FITKAcousticsVTKGraphObject3D* m_graphObject{ nullptr };
        //@}

    };
}

#endif // __PICKEDDATA_H__
